package com.gaojinqi.base.common.validation.custom;

import com.gaojinqi.base.common.enums.IEnum;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
import java.util.Objects;

/**
 * 枚举验证，允许空值
 *
 * @author gaojinqi
 * @version 1.0
 * @since 2020年05月20日
 */
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValid.EnumValidator.class)
@Repeatable(EnumValid.List.class)
public @interface EnumValid {

    String message() default "没有这个类型，请重新选择";

    /**
     * 枚举名校验
     */
    Class<? extends java.lang.Enum<?>>[] value();

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Documented
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface List {
        EnumValid[] value();
    }

    class EnumValidator implements ConstraintValidator<EnumValid, Object> {

        Class<? extends java.lang.Enum<?>>[] enums = null;

        /**
         * @see javax.validation.ConstraintValidator#initialize(java.lang.annotation.Annotation)
         */
        @Override
        public void initialize(EnumValid constraintAnnotation) {
            enums = constraintAnnotation.value();
        }

        /**
         * @see javax.validation.ConstraintValidator#isValid(java.lang.Object,
         * javax.validation.ConstraintValidatorContext)
         */
        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {

            // 允许空值
            if (o == null) {
                return true;
            }

            // 无初始化参数则无需验证
            if (enums == null || enums.length == 0) {
                return true;

            }

            // 优先检测枚举名
            String value = String.valueOf(o);

            for (Class<? extends java.lang.Enum<?>> enumCls : enums) {
                for (java.lang.Enum<?> e : enumCls.getEnumConstants()) {
                    if (IEnum.class.isAssignableFrom(enumCls)) {
                        if (Objects.equals(((IEnum) e).getCode(), o)) {
                            return true;
                        }
                    } else {
                        if (e.name().equals(value)) {
                            return true;
                        }
                    }
                }
            }


            return false;
        }


    }
}